#include "mysql_field.h"
#include <boost/lexical_cast.hpp>
#include "libzqutil/ustring.h"
#include "mysql_query.h"

namespace libzq
{
	namespace mysql
	{

		FieldValue::FieldValue(const long int v) :
			_type(LONGLONG)
		{
			_v._long = v;
		}

		FieldValue::FieldValue(const int v) :
			_type(INT)
		{
			_v._int = v;
		}

		FieldValue::FieldValue(const double v) :
			_type(DOUBLE)
		{
			_v._double = v;
		}

		FieldValue::FieldValue(const bool v) :
			_type(INT)
		{
			_v._int = v ? 1 : 0;
		}

		FieldValue::FieldValue(const char * v)
		{
			if (v == nullptr)
			{
				_type = NONE;
				_v._string = "NULL";
			}
			else
			{
				_type = STRING;

				size_t len = strlen(v);
				char* buf = new char[len + 1];
				buf[len] = '\0';
				memcpy(buf, v, len);
				_v._string = buf;
			}
		}
		FieldValue::FieldValue(const string & v)
		{
			_type = STRING;

			size_t len = v.length();
			char* buf = new char[len + 1];
			buf[len] = '\0';
			memcpy(buf, v.c_str(), len);
			_v._string = buf;
		}

		FieldValue::~FieldValue()
		{
			if (_type == STRING and _v._string)
			{
				delete[] _v._string;
				_v._string = nullptr;
			}
		}

		string FieldValue::to_string() const
		{
			switch (_type)
			{
			case NONE:
				return _v._string;
			case STRING:
				return std::move(escape());
			case LONGLONG:
				return std::move(format("%ld", _v._long));
			case INT:
				return std::move(format("%d", _v._int));
			case DOUBLE:
				return std::move(format("%f", _v._double));
			default:
				return "";
			}
		}

		string FieldValue::escape() const
		{
			string out;
			size_t len = strlen(_v._string);
			out.push_back('\'');
			for (size_t i = 0; i < len; i++)
			{
				char c = _v._string[i];
				if (c == '\'' || c == '\n' || c == '\\' || c == '\t' || c == '\b' || c == '\r')
				{
					out.push_back('\\');
					if (c == '\'')
						out.push_back('\'');
					else if (c == '\n')
						out.push_back('n');
					else if (c == '\\')
						out.push_back('\\');
					else if (c == '\t')
						out.push_back('t');
					else if (c == '\b')
						out.push_back('b');
					else if (c == '\r')
						out.push_back('r');
				}
				else
				{
					out.push_back(c);

				}
			}
			out.push_back('\'');
			return std::move(out);
		}

		FieldValue::FieldValue(FieldValue && v)
		{
			memcpy(this, &v, sizeof(v));

			if (_type == STRING)
			{
				_v._string = v._v._string;
				v._v._string = nullptr;
			}
		}

		FieldValue::FieldValue(const FieldValue & v)
		{
			memcpy(this, &v, sizeof(v));
			if (_type == STRING)
			{
				size_t len = strlen(v._v._string);
				char* buf = new char[len + 1];
				buf[len] = '\0';
				memcpy(buf, v._v._string, len);
				_v._string = buf;
			}
		}

		bool FieldValue::is_null() const
		{
			return _type == NONE;
		}

		Field::Field(MathOp op, const string && field) :
			_table(""),
			_field(field),
			_math(op)
		{
		}

		Field::Field(const string & table, const string && field) :
			_table(table),
			_field(field),
			_math(MATH_NONE)
		{
		}

		Field::Field(const string && field) :
			_table(""),
			_field(field),
			_math(MATH_NONE)
		{
		}

		Field::Field(const string & field) :
			_table(""),
			_field(field),
			_math(MATH_NONE)
		{

		}

		Field::Field(const Field & field) :
			_table(field._table),
			_field(field._field),
			_math(field._math)
		{

		}

		shared_ptr<FilterImpl> Field::operator=(const FieldValue && t)
		{
			return create(t.is_null() ? IS : EQ, t);
		}

		shared_ptr<FilterImpl> Field::operator>(const FieldValue && t)
		{
			return create(GT, t);
		}

		shared_ptr<FilterImpl> Field::operator<(const FieldValue && t)
		{
			return create(LT, t);
		}

		shared_ptr<FilterImpl> Field::operator>=(const FieldValue && t)
		{
			return create(GTE, t);
		}

		shared_ptr<FilterImpl> Field::operator<=(const FieldValue && t)
		{
			return create(LTE, t);
		}

		shared_ptr<FilterImpl> Field::operator!=(const FieldValue && t)
		{
			return create(t.is_null() ? NOT : NE, t);
		}

		shared_ptr<FilterImpl> Field::create(Operator op, const FieldValue & t)
		{
			return std::make_shared<FieldFilter>(*this, op, t);
		}

		shared_ptr<FilterImpl> Field::operator=(const Field && t)
		{
			return create(EQ, t);
		}

		shared_ptr<FilterImpl> Field::operator>(const Field && t)
		{
			return create(GT, t);
		}

		shared_ptr<FilterImpl> Field::operator<(const Field && t)
		{
			return create(LT, t);
		}

		shared_ptr<FilterImpl> Field::operator>=(const Field && t)
		{
			return create(GTE, t);
		}

		shared_ptr<FilterImpl> Field::operator<=(const Field && t)
		{
			return create(LTE, t);
		}

		shared_ptr<FilterImpl> Field::operator!=(const Field && t)
		{
			return create(NE, t);
		}

		shared_ptr<FilterImpl> Field::create(Operator op, const Field & t)
		{
			return std::make_shared<TableFilter>(*this, op, t);
		}

		string Field::to_string(const string& table) const
		{
			string&& field = _table.empty() && table.empty() ? format(_field.compare("*") ? "`%s`" : "%s", _field) : format(_field.compare("*") ? "`%s`.`%s`" : "`%s`.%s", _table.empty() ? table : _table, _field);
			if (_math)
			{
				field = format("%s(%s) as %s_%s", math_operator_[_math], field, _field, math_operator_[_math]);
			}
			return field;
		}

		Table::Table(const string && table) :
			_table(table)
		{

		}

		Field Table::field(const string && field)
		{
			return std::move(Field(_table, field.c_str()));
		}

	}
}
